﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HelloWorld.Code.Util;

namespace HelloWorld.Code.DataAccess
{
    [MetadataType(typeof(MessageMetaData))]
    public partial class Message : IDataErrorInfo, IValidatableObject
    {
        #region Validation - in a normal project you have to decide if you want to use IDataErrorInfo or IValidatableObject

        partial void OnNameChanging(string value)
        {
            if(string.IsNullOrEmpty(value) || value.Split(new []{" "}, StringSplitOptions.RemoveEmptyEntries).Length < 2)
                _errors.Add("Name", "Please enter your name and surname");
        }

        #region IDataErrorInfo Members

        public string Error { get; private set; }

        private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
        public string this[string columnName]
        {
            get
            {
                return _errors.ContainsKey(columnName) ? _errors[columnName] : string.Empty;
            }
        }

        #endregion

        #region IValidatableObject Members - this is the recommanded interface to use for complex model validation

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            //Thow an error if the subjct and the message are the same
            if (String.Compare(Subject.Trim(), Message1.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
            {
                yield return new ValidationResult("The subject and the message can't be the same.");
            }

            //Throw an error there is another message with the same subject from the same person
            using (var context = new MvcDemoEntities())
            {
                var existingMessage = context.Messages.FirstOrDefault(m => string.Compare(m.Name.Trim(), Name.Trim(), StringComparison.InvariantCultureIgnoreCase) == 0 &&
                                                                           string.Compare(m.Subject.Trim(), Subject.Trim(), StringComparison.InvariantCultureIgnoreCase) == 0);
                if(existingMessage != null)
                {
                    yield return new ValidationResult("A message with the same subject was previously saved in the DB.", new []{"Subject"});
                }
            }
        }

        #endregion

        #endregion

        /// <summary>
        /// Get a list that contains the available contact reasons to choose from
        /// </summary>
        public IEnumerable<SelectListItem> ContactReasonsList
        {
            get
            {
                return (new[]
                            {
                                new SelectListItem
                                    {
                                        Selected = (ContactReasonId == 0),
                                        Text = "Select...",
                                        Value = string.Empty
                                    }
                            }).Union(CacheManager.GetContactReasons(HttpContext.Current.Request.HttpMethod == "POST").
                                         Select(c => new SelectListItem
                                         {
                                             Selected = (c.ContactReasonId == ContactReasonId),
                                             Text = c.ContactReasonText,
                                             Value = c.ContactReasonId.ToString(CultureInfo.InvariantCulture)
                                         }));              
            }
        }

        /// <summary>
        /// Save only if it's a possitive feedback.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool Save(out string message)
        {
            try
            {
                using (var context = new MvcDemoEntities())
                {
                    if (ContactReasonId == 1) //A positive remark
                    {
                        context.Messages.AddObject(this);
                        message = "Your message was saved successfully. Thank you for your appreciation!";
                        context.SaveChanges();
                        return true;
                    }                   
                    message = "We are sorry you were disappointed.";
                    return false;                                        
                }
            }
            catch
            {
                message = "An unexpected error occured.";
                return false;
            }
        }

        public static bool EmailAlradyExists(string email, out string validationMessage)
        {
            validationMessage = string.Empty;
            using (var context = new MvcDemoEntities())
            {
                var result = context.Messages.Any(m => string.Compare(m.Email, email, StringComparison.CurrentCultureIgnoreCase) == 0);
                if (result)
                    validationMessage = "This e-mail address is already used";

                return result;
            }
        }
    }

    public class MessageMetaData
    {
        [Required(ErrorMessage = "Required")]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "The name must be a string of at least 3 characters and at most 50 characters")]
        public string Name { get; set; }

        [Remote("ValidateEmail", "Home")]
        [Required(ErrorMessage = "Required")]
        [StringLength(50, ErrorMessage = "The e-mail can't have more than 50 characters")]
        [RegularExpression(@"^\w+([-+.]*[\w-]+)*@(\w+([-.]?\w+)){1,}\.\w{2,4}$", ErrorMessage = "Invalid e-mail")]
        [Display(Name = "E-mail")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Required")]
        [Display(Name = "Contact reason")]
        public int? ContactReasonId { get; set; }

        [Required(ErrorMessage = "Required")]
        [StringLength(100, ErrorMessage = "The subject must be a string with a maximum length of 100 characters")]
        public string Subject { get; set; }

        [Required(ErrorMessage = "Required")]
        [Display(Name = "Message")]
        public string Message1 { get; set; }
    }
}